.section .text, "ax"

/* synchronous exception for EL1 */
.global vector_exception
vector_exception:
    b .

/* IRQ for EL1 */
.global vector_irq
vector_irq:
    /* the interrupt has been disabled by hardware automatically */
    /* save context */
    /* NOTE: don't save elr_el1/spsr_el1 because interrupt nesting never be happend */
    /* NOTE: maybe have a good way to save context to thread directly */
    stp x1, x0, [sp, #-16]!
    stp x3, x2, [sp, #-16]!
    stp x5, x4, [sp, #-16]!
    stp x7, x6, [sp, #-16]!
    stp x9, x8, [sp, #-16]!
    stp x11, x10, [sp, #-16]!
    stp x13, x12, [sp, #-16]!
    stp x15, x14, [sp, #-16]!
    stp x17, x16, [sp, #-16]!
    stp x19, x18, [sp, #-16]!
    stp x21, x20, [sp, #-16]!
    stp x23, x22, [sp, #-16]!
    stp x25, x24, [sp, #-16]!
    stp x27, x26, [sp, #-16]!
    stp x29, x28, [sp, #-16]!
    str x30, [sp, #-8]!
    /* enter interrupt */
    add x0, sp, #(30 * 8)       // the start address of context
    bl mx_interrupt_enter       // save the context of interrupted thread for do schedule in interrupt
    /* ack gicv3 */
    bl getICC_IAR1              // get the interrupt number (NOTE: this register can't be accessed multiple times, otherwise the interrupt can't occur)
    mov x28, x0                 // save the interrupt number following
    bl setICC_EOIR1             // ack the interrupt by interrupt number
    /* invoke interrupt distributor */
    mov x0, x28
    bl mx_interrupt_handle      // maybe not back if call `mx_thread_schedule_interrupt` in interrupt handler
    /* leave interrupt */
    bl mx_interrupt_leave
    /* restore context */
    ldr x30, [sp], #8
    ldp x29, x28, [sp], #16
    ldp x27, x26, [sp], #16
    ldp x25, x24, [sp], #16
    ldp x23, x22, [sp], #16
    ldp x21, x20, [sp], #16
    ldp x19, x18, [sp], #16
    ldp x17, x16, [sp], #16
    ldp x15, x14, [sp], #16
    ldp x13, x12, [sp], #16
    ldp x11, x10, [sp], #16
    ldp x9, x8, [sp], #16
    ldp x7, x6, [sp], #16
    ldp x5, x4, [sp], #16
    ldp x3, x2, [sp], #16
    ldp x1, x0, [sp], #16
    /* the interrupt will be enabled after ERET is called
       because the interrupt state must be enable and saved before the interrupt occurs and it will be restored after ERET */
    eret

/* FIQ for EL1 */
.global vector_fiq
vector_fiq:
    b .

/* disable all of the interrupts */
.global mx_interrupt_disable
.type mx_interrupt_disable, %function
mx_interrupt_disable:
    msr DAIFSet, #0x0F
    ret

/* enable all of the interrupts */
.global mx_interrupt_enable
.type mx_interrupt_enable, %function
mx_interrupt_enable:
    msr DAIFClr, #0x0F
    ret

/* disable all of the interrupts and return the interrupt state before closing the interrupt */
.global mx_interrupt_disable_nest
.type mx_interrupt_disable_nest, %function
mx_interrupt_disable_nest:
    mrs x0, DAIF    // Zeros(54):PSTATE.<D,A,I,F>:Zeros(6)
    msr DAIFSet, #0x0F
    ret

/* recover the interrupt state that before called mx_interrupt_disable */
.global mx_interrupt_enable_nest
.type mx_interrupt_enable_nest, %function
mx_interrupt_enable_nest:
    msr DAIF, x0
    ret
